import json
import re
import sys
from common.debugtalk import DebugTalk
from common.readyaml import get_data_yaml
from conf.setting import FILE_PATH
from conf.operactionconfig import OperactionConfig
from common.requestbase import SendRequest
from common.yamlwrite import WriterYaml
from common.recordlog import logs
from common.assertions import assert_response
import allure
import jsonpath


class BaseRequest(object):
    def __init__(self):
        self.read = WriterYaml()

    def get_replacement_value(self, match):
        """
        获取替换值
        
        Args:
            match (re.Match): 匹配结果对象
        
        Returns:
            Any: 替换后的值
        
        """
        placeholder = match.group()
        # 移除 ${ 和 }
        placeholder_content = placeholder[2:-1]

        # 提取函数名和参数
        func_match = re.match(r'(\w+)\((.*)\)', placeholder_content)
        if func_match:
            func_name = func_match.group(1)
            func_args = func_match.group(2)
        return getattr(DebugTalk(), func_name)(*func_args.split(',') if func_args else "")

    def replace_load(self, data):
        """
        将给定的data中的占位符替换为相应的值。
        
        Args:
            data (Union[str, dict]): 待替换占位符的字符串或字典。
        
        Returns:
            Union[str, dict]: 替换后的字符串或字典。
        
        """
        if not isinstance(data, str):
            data = json.dumps(data, ensure_ascii=False)

        # 使用正则表达式找到所有的占位符
        pattern = re.compile(r'\$\{[^}]+\}')
        # 替换占位符
        replaced_data = pattern.sub(self.get_replacement_value, data)
        if replaced_data and isinstance(replaced_data, str):
            replaced_data = json.loads(replaced_data)
        return replaced_data

    def case_yaml(self, baseinfo, testcase):
        """
        解析yaml数据并发起请求
        
        Args:
            baseinfo: 包含API基本信息的字典
            testcase: 包含测试用例详细信息的字典
        
        Returns:
            无返回值
        """
        """
        解析yaml数据并发起请求
        :param case_value:待解析的数据
        :return:
        """
        baseinfo = self.replace_load(baseinfo)
        testcase = self.replace_load(testcase)
        url = OperactionConfig().get_section_for_data('api_envi', 'host') + baseinfo['url']
        allure.attach(url, f'接口地址是:{url}')
        api_name = baseinfo['api_name']
        allure.attach(api_name, f'接口名称是:{api_name}')
        method = baseinfo['method']
        allure.attach(method, f'请求方式是:{method}')
        header = baseinfo['header']
        allure.attach(str(header), '请求头是:', allure.attachment_type.TEXT)
        allure.attach(str(testcase['case_name']), f'测试用例名称是:{testcase["case_name"]}', allure.attachment_type.TEXT)
        allure.attach(str(testcase['data']), '请求参数称是:', allure.attachment_type.TEXT)
        header = baseinfo['header']
        cookies = header.pop('cookies', None)
        # print(cookies,'00000000000000')
        response = SendRequest().run_main(url, method, testcase['data'], header, cookies=cookies)

        allure.attach(str(json.loads(response.text)), '响应结果是:', allure.attachment_type.TEXT)
        extract = testcase.pop('extract', None)
        validation = testcase.pop('validation', None)
        extract_list = testcase.pop('extract_list', None)
        if extract is not None:
            self.extract_data(extract, response.text)

        if extract_list is not None:
            self.extract_data_list(extract_list, response.text)
        if validation is not None:
            assert_result = assert_response(validation, response.json(), response.status_code)
            assert assert_result == True
        # data = case_value['testCase']
        # for item in data:
        #     # print(item['extract'],'000')
        #     allure.attach(str(item['case_name']), f'测试用例名称是:{item["case_name"]}', allure.attachment_type.TEXT)
        #     allure.attach(str(item['data']), '请求参数称是:', allure.attachment_type.TEXT)
        #     response = SendRequest().run_main(url, method, item['data'], header)
        #     allure.attach(str(json.loads(response.text)), '响应结果是:', allure.attachment_type.TEXT)
        #     extract = item.pop('extract', None)
        #     validation = item.pop('validation', None)
        #     extract_list = item.pop('extract_list', None)
        #     if extract is not None:
        #         self.extract_data(extract, response.text)
        #
        #     if extract_list is not None:
        #         self.extract_data_list(extract_list, response.text)
        #     if validation is not None:
        #         assert_result = assert_response(validation, response.json(), response.status_code)
        #         assert assert_result == True

    def extract_data(self, extract, response):
        """
        根据提取规则从响应中提取数据，并写入YAML文件
        
        Args:
            extract (dict): 提取规则，格式为{key: value}，其中key为提取数据的名称，value为提取规则，可以是jsonpath表达式或正则表达式
            response (str): 待提取数据的响应内容
        
        Returns:
            None
        
        """
        for key, value in extract.items():
            if "$" in value:
                extract_json = jsonpath.jsonpath(json.loads(response), value)[0]
                if extract_json is not None:
                    write_yaml_data = {key: extract_json}
                    WriterYaml().write(write_yaml_data)
                    logs.info(f"json提取结果是:{str(write_yaml_data)}")
                else:
                    logs.info("json提取器提取数据失败,请检查数据或json提取器是否正常")


            else:
                extract_reg = re.search(value, response)
                if extract_reg is not None:
                    write_extract_reg = extract_reg.group(1)
                    write_yaml_data = {key: write_extract_reg}
                    WriterYaml().write(write_yaml_data)
                    logs.info(f"正则提取结果是:{str(write_yaml_data)}")
                else:
                    logs.info("正则提取器提取数据失败,请检查数据或正则提取器是否正常")

    def extract_data_list(self, testcase_extract_list, response):
        """
        提取多个参数，支持正则表达式和json提取，提取结果以列表形式返回
        :param testcase_extract_list: yaml文件中的extract_list信息
        :param response: 接口的实际返回值,str类型
        :return:
        """
        try:
            for key, value in testcase_extract_list.items():
                if "(.+?)" in value or "(.*?)" in value:
                    ext_list = re.findall(value, response, re.S)
                    if ext_list:
                        extract_date = {key: ext_list}
                        logs.info('正则提取到的参数：%s' % extract_date)
                        self.read.write(extract_date)
                if "$" in value:
                    # 增加提取判断，有些返回结果为空提取不到，给一个默认值
                    ext_json = jsonpath.jsonpath(json.loads(response), value)
                    if ext_json:
                        extract_date = {key: ext_json}
                    else:
                        extract_date = {key: "未提取到数据，该接口返回结果可能为空"}
                    logs.info('json提取到参数：%s' % extract_date)
                    self.read.write(extract_date)
        except Exception as e:
            print(e, '0000')
            logs.error('接口返回值提取异常，请检查yaml文件extract_list表达式是否正确！')

    def clean_yaml(self, filename=FILE_PATH['extract']):
        """
        清空yaml文件
        :param filename:传入yaml文件路径
        :return:
        """
        with open(filename, 'w', encoding='utf-8') as f:
            f.truncate()

# 从 YAML 文件中读取数据
# data_from_yaml = get_data_yaml(FILE_PATH['login'])[0]
# #
# # # 创建实例并调用方法
# base_request = BaseRequest()
# base_request.case_yaml(data_from_yaml)
# print(base_request.replace_load(data_from_yaml))
